package personal.jinhui.paprika.ui;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.jivesoftware.smack.util.StringUtils;

import personal.jinhui.paprika.PaprikaApplication;
import personal.jinhui.paprika.PaprikaService;
import personal.jinhui.paprika.providers.AvatarProvider;
import personal.jinhui.paprika.service.UserInfo;
import personal.jinhui.paprika.utils.ImageHelper;
import personal.jinhui.paprika.utils.PaprikaBroadcastReceiver;
import personal.jinhui.paprika.utils.PaprikaConnectivity;
import personal.jinhui.paprika.utils.Status;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import personal.jinhui.paprika.R;
import personal.jinhui.paprika.service.aidl.IXmppFacade;

/**
 * This Activity is used to change the status.
 */
public class ChangeStatusActivity extends Activity {
	private static final String TAG = "ChangeStatusActivity";

	private static final Intent SERVICE_INTENT = new Intent();
	static {
		SERVICE_INTENT.setComponent(new ComponentName(
				"personal.jinhui.paprika",
				"personal.jinhui.paprika.PaprikaService"));
	}

	private static final int AVAILABLE_FOR_CHAT_IDX = 0;
	private static final int AVAILABLE_IDX = 1;
	private static final int BUSY_IDX = 2;
	private static final int AWAY_IDX = 3;
	private static final int UNAVAILABLE_IDX = 4;
	private static final int DISCONNECTED_IDX = 5;

	private static final int ICON_SIZE = 150;

	private static final int SELECT_PHOTO_DLG = 0;

	private static final int CAMERA_WITH_DATA = 0;
	private static final int PHOTO_PICKED_WITH_DATA = 1;

	private static final File PHOTO_DIR = new File(
			Environment.getExternalStorageDirectory() + "/DCIM/Camera");

	private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile";

	/*
	 * private static final Uri MY_AVATAR_URI = Uri
	 * .parse(AvatarProvider.CONTENT_URI + "/my_avatar");
	 */

	private EditText mStatusMessageEditText;
	private Button mOk;
	private Button mCancel;
	private Spinner mSpinner;
	private ImageView mAvatar;
	/*
	 * private static final Uri mTmpAvatarUri = Uri
	 * .parse(AvatarProvider.CONTENT_URI + "/tmp_avatar");
	 */

	private static final Uri mTmpAvatarUri = AvatarProvider.CONTENT_URI
			.buildUpon().appendPath("/tmp_avatar").build();

	private static Uri mAvatarUri;

	private SharedPreferences mSettings;
	private ArrayAdapter<CharSequence> mAdapter;

	private IXmppFacade mXmppFacade;
	private UserInfo mUserInfo;

	private final ServiceConnection mServConn = new PaprikaServiceConnection();
	private final OnClickListener mOnClickOk = new MyOnClickListener();
	private final PaprikaBroadcastReceiver mReceiver = new PaprikaBroadcastReceiver();
	private boolean mDisableAvatar;
	private File mCurrentPhotoFile;

	private static final int NEED_UPDATE = 1;

	/**
	 * Constructor.
	 */
	public ChangeStatusActivity() {
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		Log.d(TAG, "oncreate");
		setContentView(R.layout.change_status);

		mOk = (Button) findViewById(R.id.ChangeStatusOk);
		mOk.setOnClickListener(mOnClickOk);

		mCancel = (Button) findViewById(R.id.ChangeStatusCancel);
		mCancel.setOnClickListener(mOnClickOk);

		PaprikaApplication app = (PaprikaApplication) getApplication();
		mAvatar = (ImageView) findViewById(R.id.avatarButton);
		mAvatar.setOnClickListener(mOnClickOk);
		if (!app.isPepEnabled()) {
			View avatarPanel = findViewById(R.id.panel_1);
			avatarPanel.setVisibility(View.GONE);
		}

		mSettings = PreferenceManager.getDefaultSharedPreferences(this);
		mStatusMessageEditText = (EditText) findViewById(R.id.ChangeStatusMessage);
		mStatusMessageEditText.setText(mSettings.getString(
				PaprikaApplication.STATUS_TEXT_KEY, ""));

		mSpinner = (Spinner) findViewById(R.id.ChangeStatusSpinner);
		mAdapter = ArrayAdapter.createFromResource(this, R.array.status_types,
				R.layout.simple_spinner_item2);
		mAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		mSpinner.setAdapter(mAdapter);
		mSpinner.setSelection(getPreferenceStatusIndex());

		this.registerReceiver(mReceiver, new IntentFilter(
				PaprikaBroadcastReceiver.Paprika_CONNECTION_CLOSED));

		// mAvatarManager.addAvatarListener(new AvatarEventListener());
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onResume() {
		super.onResume();
		if (!PaprikaConnectivity.isConnected(getApplicationContext())) {
			Intent i = new Intent(this, LoginActivity.class);
			startActivity(i);
			finish();
		}
		bindService(new Intent(this, PaprikaService.class), mServConn,
				BIND_AUTO_CREATE);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void onPause() {
		super.onPause();
		unbindService(mServConn);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see android.app.Activity#onDestroy()
	 */
	@Override
	protected void onDestroy() {
		super.onDestroy();
		this.unregisterReceiver(mReceiver);
	}

	/*
	 * The activity is often reclaimed by the system memory.
	 */
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		if (mCurrentPhotoFile != null) {
			outState.putString(KEY_CURRENT_PHOTO_FILE,
					mCurrentPhotoFile.toString());
		}
		super.onSaveInstanceState(outState);
	}

	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		String fileName = savedInstanceState.getString(KEY_CURRENT_PHOTO_FILE);
		if (fileName != null) {
			mCurrentPhotoFile = new File(fileName);
		}
		super.onRestoreInstanceState(savedInstanceState);
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		if (id == SELECT_PHOTO_DLG)
			return createPickPhotoDialog();
		return null;
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// Ignore failed requests
		if (resultCode != RESULT_OK)
			return;

		switch (requestCode) {
		case PHOTO_PICKED_WITH_DATA:
			// We tell the activity to put the result in mAvatarUri
			Log.d(TAG, "selected avatar uri " + mAvatarUri);
			mDisableAvatar = false;
			mAvatar.setImageURI(mAvatarUri);
			// publishAvatar();
			break;

		case CAMERA_WITH_DATA:
			doCropPhoto(mCurrentPhotoFile);
			// publishAvatar();
			break;
		default:
			Log.w(TAG, "onActivityResult : invalid request code");

		}
	}

	/**
	 * Return the status index from status the settings.
	 * 
	 * @return the status index from status the settings.
	 */
	private int getPreferenceStatusIndex() {
		return mSettings.getInt(PaprikaApplication.STATUS_KEY, AVAILABLE_IDX);
	}

	/**
	 * Return the status text from status the settings.
	 * 
	 * @param id
	 *            status text id.
	 * @return the status text from status the settings.
	 */
	private String getPreferenceString(int id) {
		return mSettings.getString(getString(id), "");
	}

	/**
	 * convert status text to.
	 * 
	 * @param item
	 *            selected item text.
	 * @return item position in the array.
	 */
	private int getStatusForService(String item) {
		int result;
		switch (mAdapter.getPosition(item)) {
		case ChangeStatusActivity.DISCONNECTED_IDX:
			result = Status.CONTACT_STATUS_DISCONNECT;
			break;
		case ChangeStatusActivity.AVAILABLE_FOR_CHAT_IDX:
			result = Status.CONTACT_STATUS_AVAILABLE_FOR_CHAT;
			break;
		case ChangeStatusActivity.AVAILABLE_IDX:
			result = Status.CONTACT_STATUS_AVAILABLE;
			break;
		case ChangeStatusActivity.AWAY_IDX:
			result = Status.CONTACT_STATUS_AWAY;
			break;
		case ChangeStatusActivity.BUSY_IDX:
			result = Status.CONTACT_STATUS_BUSY;
			break;
		case ChangeStatusActivity.UNAVAILABLE_IDX:
			result = Status.CONTACT_STATUS_UNAVAILABLE;
			break;
		default:
			result = Status.CONTACT_STATUS_AVAILABLE;
			break;
		}
		return result;
	}

	/**
	 * ClickListener for the avatarButton.
	 * 
	 * @param button
	 *            the avatar button
	 */
	@SuppressWarnings("deprecation")
	private void onAvatarButton(View button) {
		showDialog(SELECT_PHOTO_DLG);
	}

	/*
	 * Some codes from AOSP (platform/packages/apps/Contacts) to select and crop
	 * an image.
	 */

	/**
	 * Creates a dialog offering two options: take a photo or pick a photo from
	 * the gallery.
	 * 
	 * @return the dialog
	 */
	private Dialog createPickPhotoDialog() {
		// Wrap our context to inflate list items using correct theme
		final Context dialogContext = new ContextThemeWrapper(this,
				android.R.style.Theme_Light);

		final ListAdapter adapter = ArrayAdapter.createFromResource(
				dialogContext, R.array.pick_photo_items,
				android.R.layout.simple_list_item_1);

		final AlertDialog.Builder builder = new AlertDialog.Builder(
				dialogContext);
		builder.setTitle(R.string.select_avatar);
		builder.setSingleChoiceItems(adapter, -1,
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
						switch (which) {
						case 0:
							doTakePhoto();
							break;
						case 1:
							doPickPhotoFromGallery();
							break;
						case 2:
							mDisableAvatar = true;
							mAvatar.setImageURI(null);
							break;
						default:
							Log.w(TAG,
									"DialogInterface onClick : invalid which code");
						}
					}
				});
		return builder.create();
	}

	/**
	 * Create a file name for the icon photo using current time.
	 * 
	 * @return the filename
	 */
	private String getPhotoFileName() {
		Date date = new Date(System.currentTimeMillis());
		SimpleDateFormat dateFormat = new SimpleDateFormat(
				"'IMG'_yyyyMMdd_HHmmss");
		return dateFormat.format(date) + ".jpg";
	}

	/**
	 * Launches Camera to take a picture and store it in a file.
	 */
	protected void doTakePhoto() {
		try {
			// Launch camera to take photo for selected contact
			PHOTO_DIR.mkdirs();
			mCurrentPhotoFile = new File(PHOTO_DIR, getPhotoFileName());
			final Intent intent = getTakePickIntent(mCurrentPhotoFile);
			startActivityForResult(intent, CAMERA_WITH_DATA);
		} catch (ActivityNotFoundException e) {
			Toast.makeText(this, R.string.photoPickerNotFoundText,
					Toast.LENGTH_LONG).show();
		}
	}

	/**
	 * Constructs an intent for capturing a photo and storing it in a temporary
	 * file.
	 * 
	 * @param f
	 *            the temporary file to use to store the picture
	 * @return the intent
	 */
	public Intent getTakePickIntent(File f) {
		Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE, null);
		intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
		return intent;
	}

	/**
	 * Sends a newly acquired photo to Gallery for cropping.
	 * 
	 * @param f
	 *            the image file to crop
	 */
	protected void doCropPhoto(final File f) {
		try {

			// Add the image to the media store
			// level 8
			/*
			 * MediaScannerConnection.scanFile( this, new String[] {
			 * f.getAbsolutePath() }, new String[] { null }, null);
			 */

			// Launch gallery to crop the photo
			final Intent intent = getCropImageIntent(Uri.fromFile(f));
			startActivityForResult(intent, PHOTO_PICKED_WITH_DATA);
		} catch (ActivityNotFoundException e) {
			Log.e(TAG, "Cannot crop image", e);
			Toast.makeText(this, R.string.photoPickerNotFoundText,
					Toast.LENGTH_LONG).show();
		}
	}

	/**
	 * Constructs an intent for image cropping.
	 * 
	 * @param photoUri
	 *            the uri of the photo to crop
	 * @return the intent
	 */
	public Intent getCropImageIntent(Uri photoUri) {
		Intent intent = new Intent("com.android.camera.action.CROP");
		intent.setDataAndType(photoUri, "image/*");
		intent.putExtra("crop", "true");
		intent.putExtra("aspectX", 1);
		intent.putExtra("aspectY", 1);
		intent.putExtra("outputX", ICON_SIZE);
		intent.putExtra("outputY", ICON_SIZE);
		intent.putExtra(MediaStore.EXTRA_OUTPUT, mAvatarUri);
		return intent;
	}

	/**
	 * Launches Gallery to pick a photo.
	 */
	protected void doPickPhotoFromGallery() {
		try {
			// Launch picker to choose photo for selected contact
			final Intent intent = getPhotoPickIntent();
			startActivityForResult(intent, PHOTO_PICKED_WITH_DATA);
		} catch (ActivityNotFoundException e) {
			Toast.makeText(this, R.string.photoPickerNotFoundText,
					Toast.LENGTH_LONG).show();
		}
	}

	/**
	 * Constructs an intent for picking a photo from Gallery, cropping it and
	 * returning the bitmap.
	 * 
	 * @return the intent
	 */
	public Intent getPhotoPickIntent() {
		Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
		intent.setType("image/*");
		intent.putExtra("crop", "true");
		intent.putExtra("aspectX", 1);
		intent.putExtra("aspectY", 1);
		intent.putExtra("outputX", ICON_SIZE);
		intent.putExtra("outputY", ICON_SIZE);
		intent.putExtra(MediaStore.EXTRA_OUTPUT, mAvatarUri);
		// use this to get the bitmap in the intent
		// intent.putExtra("return-data", true);
		return intent;
	}

	private Bitmap getMyAvatarBmp() {
		Bitmap bmp = null;
		SharedPreferences pref = PreferenceManager
				.getDefaultSharedPreferences(this);
		String fName = mUserInfo.getJid();
		String filePath = Environment.getExternalStorageDirectory()
				+ "/Android/data/personal.jinhui.paprika/cache/avatar/" + fName;
		File f = new File(filePath);
		if (f.exists()) {
			bmp = BitmapFactory.decodeFile(filePath);
		} else {
			bmp = BitmapFactory.decodeResource(getResources(),
					R.drawable.default_man);
		}

		return ImageHelper.getRoundedCornerBitmap(bmp, 8);
	}

	/**
	 * connection to service.
	 */
	private class PaprikaServiceConnection implements ServiceConnection {

		/**
		 * constructor.
		 */
		public PaprikaServiceConnection() {
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mXmppFacade = IXmppFacade.Stub.asInterface(service);
			try {
				mUserInfo = mXmppFacade.getUserInfo();
				String fName = mUserInfo.getJid();
				mAvatarUri = AvatarProvider.CONTENT_URI.buildUpon()
						.appendPath(fName).build();
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			mAvatar.setImageBitmap(getMyAvatarBmp());
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public void onServiceDisconnected(ComponentName name) {
			mXmppFacade = null;
		}
	}

	/**
	 * User have clicked on ok.
	 */
	private class MyOnClickListener implements OnClickListener {

		/**
		 * constructor.
		 */
		public MyOnClickListener() {
		}

		@Override
		public void onClick(View v) {
			if (v == mOk) {
				String msg = mStatusMessageEditText.getText().toString();
				int status = getStatusForService((String) mSpinner
						.getSelectedItem());
				Editor edit = mSettings.edit();
				edit.putString(PaprikaApplication.STATUS_TEXT_KEY, msg);
				if (status == Status.CONTACT_STATUS_DISCONNECT) {
					stopService(new Intent(ChangeStatusActivity.this,
							PaprikaService.class));
				} else {
					try {
						mXmppFacade.changeStatus(status, msg.toString());
						edit.putInt(PaprikaApplication.STATUS_KEY,
								mSpinner.getSelectedItemPosition());
						// wait for changing status finish
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						// publishAvatar();
						try {
							if (mDisableAvatar)
								mXmppFacade.disableAvatarPublishing();
							mXmppFacade.publishAvatar(mAvatarUri);
						} catch (RemoteException e) {
							Log.e(TAG, "Error while publishing avatar", e);
						}
					} catch (RemoteException e) {
						e.printStackTrace();
					}
					Toast.makeText(ChangeStatusActivity.this,
							R.string.ChangeStatusOk, Toast.LENGTH_LONG).show();
				}
				edit.commit();
				setResult(Activity.RESULT_OK);
				finish();
			} else if (v == mCancel) {
				// mStatusMessageEditText.setText(null);
				finish();
			} else if (v == mAvatar)
				onAvatarButton(v);
		}
	}
}
